package com.mokairui.stream;

import com.mokairui.util.Employee;
import com.mokairui.util.EmployeeData;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/**
 * @Description
 *          1. Stream 关注的是对数据的运算, 与 CPU 打交道
 *             集合关注的是数据的存储, 与内存打交道
 *          2. Stream 不会自己存储元素
 *             Stream 不会改变源对象, 会返回一个持有结果的新Stream
 *             Stream 操作是延迟执行的, 这意味着他们需要结果的时候才执行
 *          3. Stream 创建 API
 *              通过集合获取
 *              Stream<E> stream(): 返回一个顺序流
 *              Stream<E> parallelStream(): 返回并行流
 *
 *              通过数组获取
 *              Stream<T> stream(T[] array): 返回一个流
 *              Stream<T> of(T... args)
 *
 *              创建无限流
 *              Stream<T> iterate(final T seed, final UnaryOperator<T> f)
 *              Stream<T> generate(Supplier<T> s)
 *
 *          4. Stream 操作 API
 *              1) 筛选与切片
 *              filter(Predicate p) 接收 Lambda, 从流中排除某些元素
 *              distinct() 筛选, 通过流所生成元素的 hashCode() 和 equals() 去除重复的元素
 *              limit(long maxSize) 截断流, 使其元素不超过给定数量
 *              skip(long n) 跳过元素, 返回一个扔掉了前 n 个元素的流. 若流中元素不足 n 个, 则返回一个空流. 与 limit(n)互补
 *
 *              2) 映射
 *              map(Function f) 接收一个函数, 该函数会被应用到每个元素上, 并将其映射成一个新的元素
 *              mapToDouble(ToDoubleFunction f) 接收一个函数作为参数, 该函数会被应用到每个元素上, 产生一个新的 DoubleStream
 *              mapToInt(ToIntFunction f) 同上, 产生一个新的 IntStream
 *              mapToLong(ToLongFunction f) 同上, 产生一个新的 LongStream
 *              flatMap(Function f) 接收一个函数作为参数, 将流中的每个值都换成另外一个流, 然后把所有的流连接成一个流
 *
 *              3) 排序
 *              sorted() 产生一个新的流, 其中按自然顺序排序
 *              sorted(Comparator com) 产生一个新流, 其中按比较器顺序排序
 *
 *          5. Stream 终端 API
 *              1) 查找
 *              allMatch(Predicate p) 检查是否匹配所有元素
 *              anyMatch(Predicate p) 检查是否至少匹配一个元素
 *              noneMatch(Predicate p) 检查是否没有匹配所有元素
 *              findFirst() 返回第一个元素
 *              findAny() 返回当前流中的任意元素
 *
 *              2) 规约
 *              reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来, 得到一个值. 返回 T
 *              reduce(BinaryOperator b) 可以将流中元素返回结合起来, 得到一个值. 返回 Optional<T>
 *
 *              3) 收集
 *              collect(Collector c) 元素汇总
 * @Author Mokairui
 * @Since 2021/11/6
 */
@Slf4j(topic = "c.Stream")
public class StreamAPIDemo {
    @Test
    public void testInfiniteFlow() {
        // 创建无线流
        // 迭代 遍历前 10 个偶数
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);

        // 生成
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }

    @Test
    public void testOperator() {
        List<Employee> employees = EmployeeData.getEmployees();
        // filter
        employees.stream().filter(it -> it.getSalary() > 7000).forEach(System.out::println);
        // map
        employees.stream().map(Employee::getName).forEach(System.out::println);
        // flatMap 在 flatMap 中生成多个新的流对象 最后合并为一个流
        employees.stream().map(Employee::getName).flatMap(it -> {
            List<Character> list = new ArrayList<>();
            for (Character c : it.toCharArray()) {
                list.add(c);
            }
            return list.stream();
        }).forEach(System.out::print);
    }

}
